﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Blogical.Tools.BizTalkUndeployHelper
{
    class AssemblyHelper
    {
        public List<BizTalkAssembly> Assemblies = new List<BizTalkAssembly>();

        public void SetReferences()
        {
            foreach (BizTalkAssembly btsAssembly in this.Assemblies)
            {
                Assembly a = Assembly.Load(btsAssembly.Luid);
                foreach (AssemblyName assemblyName in a.GetReferencedAssemblies())
                {
                    BizTalkAssembly parent = this.GetAssemblyByLuid(assemblyName.FullName);
                    if (parent != null)
                    {
                        if (!btsAssembly.ParentAssemblies.Contains(parent))
                            btsAssembly.ParentAssemblies.Add(parent);

                        if (!parent.ChildAssemblies.Contains(btsAssembly))
                            parent.ChildAssemblies.Add(btsAssembly);
                    }

                }
            }
        }
        public BizTalkAssembly GetAssemblyByLuid(string luid)
        {
            var btsAssemblies =
                    from a in this.Assemblies
                    where a.Luid == luid
                    select a;
            if (btsAssemblies.Count() == 0)
                return null;
            else
                return (BizTalkAssembly)btsAssemblies.First();

        }
        public List<BizTalkAssembly> GetAutonomusAssemblies()
        {
            List<BizTalkAssembly> ret = new List<BizTalkAssembly>();
            var btsAssemblies =
                        from a in this.Assemblies
                        where a.ParentAssemblies.Count == 0
                        select a;
            foreach (BizTalkAssembly btsassembly in btsAssemblies)
                ret.Add(btsassembly);

            return ret;

        }
        public List<BizTalkAssembly> GetBuildOrder()
        {
            List<BizTalkAssembly> buildOrder_1 = new List<BizTalkAssembly>();
            List<BizTalkAssembly> buildOrder_2 = new List<BizTalkAssembly>();
            List<BizTalkAssembly> tempBuildOrder = new List<BizTalkAssembly>();
            
            foreach (BizTalkAssembly topAssembly in GetAutonomusAssemblies())
                topAssembly.GetChildAssemblies(buildOrder_1);
            
            foreach (BizTalkAssembly topAssembly in GetAutonomusAssemblies())
                topAssembly.GetChildAssemblies(tempBuildOrder);

            while (tempBuildOrder.Count > 0)
            {
                foreach (BizTalkAssembly topAssembly in buildOrder_1)
                    ProcessBuildOrder(topAssembly, tempBuildOrder, buildOrder_2);
            }
            return buildOrder_2;
        }
        bool ProcessBuildOrder(BizTalkAssembly topAssembly, List<BizTalkAssembly> assemblyList, List<BizTalkAssembly> buildOrder)
        {
            foreach (BizTalkAssembly assembly in topAssembly.ChildAssemblies)
            {
                foreach (BizTalkAssembly child in assembly.ChildAssemblies)
                {
                    if (assemblyList.Contains(child))
                        return false;
                }
            }
            buildOrder.Add(topAssembly);
            assemblyList.Remove(topAssembly);
            return true;
        }
    }
    public class BizTalkAssembly
    {
        //public BizTalkAssembly(string luid)
        //{
        //    this.Luid = luid;
        //}
        public string Luid { get; set; }
        public string Application { get; set; }
        public List<BizTalkAssembly> ParentAssemblies = new List<BizTalkAssembly>();
        public List<BizTalkAssembly> ChildAssemblies = new List<BizTalkAssembly>();
        public void GetChildAssemblies(List<BizTalkAssembly> buildOrder)
        {
            foreach (BizTalkAssembly childAssembly in this.ChildAssemblies)
                childAssembly.GetChildAssemblies(buildOrder);
    
            if(!buildOrder.Contains(this))
                buildOrder.Add(this);
        }
        public override string ToString()
        {
            return this.Luid;
        }
    }
}
